package be.ipl.finito.usecasesImpl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.ObjectNotFoundException;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import be.ipl.finito.dao.CaseDao;
import be.ipl.finito.dao.JetonDao;
import be.ipl.finito.dao.JoueurDao;
import be.ipl.finito.dao.PartieDao;
import be.ipl.finito.dao.PlateauDao;
import be.ipl.finito.domaine.Case;
import be.ipl.finito.domaine.Jeton;
import be.ipl.finito.domaine.Joueur;
import be.ipl.finito.domaine.Partie;
import be.ipl.finito.domaine.Partie.Etat;
import be.ipl.finito.domaine.Plateau;
import be.ipl.finito.exceptions.ActionImpossibleException;
import be.ipl.finito.exceptions.CreationPartieImpossibleException;
import be.ipl.finito.exceptions.JoueurDejaPresentException;
import be.ipl.finito.exceptions.PartieExistanteException;
import be.ipl.finito.usecases.GestionPartie;
import be.ipl.finito.util.Util;

@Singleton
@Startup
public class GestionPartieImpl implements GestionPartie {

	public static GestionPartieImpl instance;
	public static List<Jeton> jetons = null;

	@EJB
	PartieDao partieDao;
	@EJB
	JoueurDao joueurDao;
	@EJB
	JetonDao jetonDao;
	@EJB
	PlateauDao plateauDao;
	@EJB
	CaseDao caseDao;

	public static GestionPartieImpl getInstance() {
		if (instance == null) {
			instance = new GestionPartieImpl();
		}
		return instance;
	}

	@Override
	public List<Jeton> creerJeton() {
		if (jetons == null) {
			for (int i = 1; i <= 12; i++) {
				jetonDao.enregistrer(new Jeton(i));
				jetons = jetonDao.lister();
			}
		}
		return jetons;
	}

	@Override
	public Partie rejoindrePartie(String nomPartie, Joueur joueur)
			throws ObjectNotFoundException, JoueurDejaPresentException {
		Util.checkObject(joueur, "Le joueur");
		Util.checkString(nomPartie, "Le nom de la partie");
		Partie partie = getPartie(nomPartie);

		Plateau plateau = partie.ajouterJoueur(joueur);

		plateauDao.enregistrer(plateau);
		partieDao.mettreAJour(partie);
		return partie;
	}

	@Override
	public Partie lancerPartie(Partie partie) throws ObjectNotFoundException,
			ActionImpossibleException {

		partie = partie.lancerPartie();
		partieDao.mettreAJour(partie);

		return partie;
	}

	@Override
	public Partie creerPartie(String nomPartie, Joueur joueur)
			throws PartieExistanteException, CreationPartieImpossibleException {
		Util.checkObject(joueur, "Le joueur");
		Util.checkString(nomPartie, "Le nom de la partie");

		try {
			partieDao.rechercher(nomPartie);
			throw new PartieExistanteException(
					"Une partie de ce nom existe deja.");
		} catch (ObjectNotFoundException e) {
		}

		List<Plateau> plateaux = joueur.getPlateaux();
		for (Plateau plateau : plateaux) {
			if (plateau.getPartie().getEtat() != Etat.SUSPENDUE
					|| plateau.getPartie().getEtat() != Etat.FINIE)
				throw new CreationPartieImpossibleException(
						"Vous ne pouvez pas creer de partie car vous etes deja dans une partie");
		}

		creerJeton();

		List<Jeton> listeJetons = new ArrayList<Jeton>(jetons);
		List<Jeton> listeJetonsShuffle = new ArrayList<Jeton>();
		Collections.shuffle(listeJetons);

		for (int i = 0; i < listeJetons.size(); i++) {
			listeJetonsShuffle.add(listeJetons.get(i));
		}

		joueurDao.recharger(joueur.getIdJoueur());
		Partie partie = new Partie(nomPartie, joueur, listeJetonsShuffle);
		partieDao.enregistrer(partie);
		plateauDao.enregistrer(partie.getPlateau(joueur));

		return partie;
	}

	@Override
	public Partie reprendrePartie(String nomPartie)
			throws ObjectNotFoundException {
		Util.checkString(nomPartie, "Le nom de la partie");
		Partie partie = partieDao.rechercher(nomPartie);
		if (partie.getEtat() != Etat.SUSPENDUE)
			throw new ObjectNotFoundException(
					"La partie recherchee n'est pas suspendue");
		partie.reprendre();

		List<Plateau> plateaux = plateauDao.lister(nomPartie);
		for (Plateau p : plateaux) {
			p.setCasesOccupees(caseDao.rechercherCasesOccupees(p));
			p.setjetonsAPoserCalculer(partie);
		}
		partie.setPlateaux(plateaux);

		partieDao.mettreAJour(partie);

		return partie;
	}

	@Override
	public int lancerDe(Partie partie) throws ObjectNotFoundException {

		return partie.lanceDe();
	}

	@Override
	@Lock(LockType.READ)
	public List<Joueur> estVainqueur(Partie partie)
			throws ObjectNotFoundException {

		return partie.estVainqueur();
	}

	@Override
	public Partie suspendrePartie(Partie partie) throws ObjectNotFoundException {

		partie = partie.suspendre();

		List<Plateau> plateaux = partie.getPlateaux();
		for (Plateau plateau : plateaux)
			plateauDao.mettreAJour(plateau);
		partieDao.mettreAJour(partie);
		return partie;
	}

	@Override
	@Lock(LockType.READ)
	public List<Partie> listerParties() {
		return partieDao.lister();
	}

	@Override
	@Lock(LockType.READ)
	public List<Partie> listerPartiesSuspendues(Joueur joueur) {
		Util.checkObject(joueur, "Le nom du joueur");
		joueurDao.recharger(joueur.getIdJoueur());
		return partieDao.listerPartiesSuspendues(joueur);
	}

	@Override
	@Lock(LockType.READ)
	public List<Partie> listerPartiesEnAttente() {
		List<Partie> parties = partieDao.listerPartiesEnAttente();
		for (Partie p : parties) {
			p.setPlateaux(plateauDao.lister(p.getNom()));
		}
		return parties;
	}

	@Override
	public Partie getPartie(String nomPartie) throws ObjectNotFoundException {

		Partie partie = partieDao.rechercher(nomPartie);

		List<Plateau> plateaux = plateauDao.lister(nomPartie);
		partie.setPlateaux(plateaux);

		for (Plateau p : plateaux) {
			List<Case> cases = caseDao.rechercherCasesOccupees(p);
			p.setCasesOccupees(cases);

			List<Jeton> jetons = new ArrayList<Jeton>();
			int i = partie.getIndiceTirage();

			if (partie.getPlaceJetons().get(i) != null)
				jetons.add(partie.getPlaceJetons().get(i));
			if (partie.getPlaceJetons().get(i + 1) != null)
				jetons.add(partie.getPlaceJetons().get(i + 1));
			if (partie.getPlaceJetons().get(i + 2) != null)
				jetons.add(partie.getPlaceJetons().get(i + 2));

			p.setJetonsAPoser(jetons);
		}

		return partie;
	}

	@Override
	public Partie commencerTourSuivant(Partie partie)
			throws ObjectNotFoundException {
		partie = partie.commencerTourSuivant();
		partieDao.mettreAJour(partie);
		return partie;
	}

	@Override
	public boolean verifierTourFini(Partie partie) {
		List<Joueur> joueurs = partie.getJoueurs();
		int tourPartie = partie.getTour();
		boolean tourFini = true;
		for (Joueur joueur : joueurs) {
			if (partie.getPlateau(joueur).getTourJoue() == tourPartie)
				tourFini = false;
		}
		return tourFini;
	}

	@Override
	public Partie supprimerPartie(Partie partie) {
		
		
		List<Plateau> plateaux = partie.getPlateaux();
		
		for(Plateau p: plateaux) {
			List<Case> cases = p.getCasesOccupees();
			for(Case c: cases) {
				caseDao.supprimer(c.getId());
			}
			
			plateauDao.supprimer(p.getIdPlateau());
		}
		
		partieDao.supprimer(partie.getId_partie());
		return partie;
	}

}
